drag and drop是一組的拖放動作,不會單獨被定義。
table view使用hasActiveDrag確認表格列是否正被拖曳且還沒被放置,而用hasActiveDrop確認table目前有無追蹤被放置的表格列。
另外使用dragInteractionEnabled來允許在2個app間進行拖放。這個值在iPad預設為true,而在iPhone的預設為false。
想在table裡增加拖曳的功能的話,需要採用UITableViewDragDelegate這個protocol,並定義tableView(:itemsForBeginning:at:)。
當你拖曳row的時候,table會回傳起始row的indexPath及其他資訊給delegate並呼叫tableView(:itemsForBeginning:at:),而你需要建立一個UIDragItem的陣列存放該row的內容回傳。若回傳空陣列,代表指定的row不允許被拖曳。
而呼叫一次function只能處理一個row,所以如果你一次選取3個row並拖曳,則此function會被同時呼叫3次。
如果已經有drag session,想加入item進現有的session,則需要定義tableView(:itemsForAddingTo:at:point:),如果沒有定義這個function,使用者的額外動作將變成一般的表格互動(例如選取與取消選取)。
當drag session存在且使用者點擊表格列的時候就會呼叫這個function,並和tableView(:itemsForBeginning:at:)一樣回傳一個存放row內容的UIDragItem的陣列。
拖放表格列時,在表格列確定要被拖放且浮起後會呼叫tableView(:dragSessionWillBegin:),可藉此定義與拖放有關的動作;而在拖放結束時呼叫tableView(:dragSessionDidEnd:),使用該方法關閉任何與拖放相關的處理程序。
另外使用tableView(:dragSessionIsRestrictedToDraggingApplication:)限制使用者只能拖放表格列到同一個app,true為只能拖放到同一個app。如果沒有定義這個function,則預設值為false。
使用tableView(:dragSessionAllowsMoveOperation:)限制表格列能否被移動,true為可移動。如果沒有定義這個function,則預設值為true。
如果需要客製化拖放時的表格列顯示,可以使用tableView(_:dragPreviewParametersForRowAt:)回傳一個UIDragPreviewParameters來對特定indexPath的row指定拖放時的顯示狀態。若回傳nil,則會是預設的顯示狀態。
當然你拖曳表格列,總不可能吃睡時手指頭都在螢幕上完成,一直壓著螢幕不放,所以就需要同時定義放至拖曳物件的功能。
想要增加這個功能,就需要採用UITableViewDropDelegate這個protocol,並定義tableView(:performDropWith:)。
tableView(:performDropWith:)是用來合併拖放的資料進表格的資料結構中,並更新表格的一個function。當你放置拖曳物件的行為產生時,table將自行產生一個UITableViewDropCoordinator,將此protocol發送給delegate並呼叫tableView(_:performDropWith:)。
呼叫此function時,他會取回drap delegate所回傳的UIDragItem陣列並進行迭代,使用結果更新表格及data source。
如何更新表格取決於拖放的物件以及需不需要非同步讀取。
直接更新table時,可以使用UITableViewDropCoordinator裡的五件去設計drop的動畫。例如可以使用drop(_:toRowAt:)設計插入脫放物件到指定位置的動畫。而剛剛提到的placeholder rows則會自動產生適合的動畫。
下一回是UITableView的完結篇!(應該吧)
到底能不能從深淵裡爬出來呢~~~~~